package com.zhz.system.biz;

import com.google.common.collect.Lists;
import com.zhz.common.enums.BizResponseEnum;
import com.zhz.common.tool.mybatisplus.base.core.contract.Page;
import com.zhz.common.tool.mybatisplus.base.core.contract.PageParam;
import com.zhz.common.utils.ConvertUtils;
import com.zhz.model.system.contract.dto.PermissionDTO;
import com.zhz.model.system.contract.dto.RoleDTO;
import com.zhz.model.system.contract.dto.RolePermissionDTO;
import com.zhz.model.system.contract.param.PermissionQueryParam;
import com.zhz.model.system.contract.param.RolePermissionQueryParam;
import com.zhz.model.system.contract.param.RoleQueryParam;
import com.zhz.system.contract.enums.PermissionTypeEnum;
import com.zhz.system.contract.request.RoleDeleteRequest;
import com.zhz.system.contract.request.RoleFindByIdRequest;
import com.zhz.system.contract.request.RoleSaveRequest;
import com.zhz.system.contract.request.RoleUpdateRequest;
import com.zhz.system.contract.response.RoleFindAllResponse;
import com.zhz.system.contract.response.RoleFindByIdResponse;
import com.zhz.system.contract.response.RoleFindByPageResponse;
import com.zhz.system.repository.service.PermissionService;
import com.zhz.system.repository.service.RolePermissionService;
import com.zhz.system.repository.service.RoleService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 角色业务处理
 *
 * @author zhouhengzhe
 * @date 2023/4/2
 */
@Slf4j
@Service
public class RoleBizService {

    @Autowired
    private RoleService roleService;

    @Autowired
    private PermissionService permissionService;

    @Autowired
    private RolePermissionService rolePermissionService;

    /**
     * 完成权限分配 todo 后期代码改造
     *
     * @param roleId  主键ID
     * @param permIds 权限ID列表
     */
    @Transactional(rollbackFor = Exception.class)
    public void assignPerms(String roleId, List<String> permIds) {
        //1.获取分配的角色对象']'

        RoleDTO roleDto = getRoleById(roleId);
        //2.构造角色的权限集合
        Set<PermissionDTO> perms = new HashSet<>();
        for (String permId : permIds) {
            //2.1、获取角色权限集合
            PermissionDTO permissionDto = getPermissionById(permId);
            //2.2、需要根据父id和类型查询API权限列表
            List<PermissionDTO> apiList = findByTypeAndPid(PermissionTypeEnum.PERMISSION_API.getCode(), permissionDto.getId());
            Set<PermissionDTO> permissionDtoSet = new HashSet<>(apiList);
            //自定赋予API权限
            perms.addAll(permissionDtoSet);//自定赋予API权限
            //当前菜单或按钮的权限
            perms.add(permissionDto);//当前菜单或按钮的权限
        }
        //获取已有的角色与权限
        List<RolePermissionDTO> list = rolePermissionService.list(
                RolePermissionQueryParam.builder()
                        .roleId(roleDto.getId())
                        .build()
        );
        List<String> oldPermissionIds = list.stream().map(RolePermissionDTO::getPermissionId).collect(Collectors.toList());
        List<String> newPermissionIds = perms.stream().map(PermissionDTO::getId).collect(Collectors.toList());
        //差集（5），数据库有的，前端没有
        Set<String> difference = oldPermissionIds.stream().filter(item -> !newPermissionIds.contains(item)).collect(Collectors.toSet());

        //获取差集的ID信息
        List<RolePermissionDTO> rolePermissions = rolePermissionService.list(
                RolePermissionQueryParam.builder()
                        .roleId(roleDto.getId())
                        .permissionIdSet(difference)
                        .build()
        );
        List<String> ids = rolePermissions.stream().map(RolePermissionDTO::getId).collect(Collectors.toList());
        //删除差集
        rolePermissionService.delete(ids);
        //去重数据，删除掉未有的，添加
        //差集（5）,前端有的，数据库没有
        Set<String> newDifference = newPermissionIds.stream().filter(item -> !oldPermissionIds.contains(item)).collect(Collectors.toSet());
        //获取角色权限ID
        Set<RolePermissionDTO> rolePermissionDtoSet = newDifference.stream().map(i ->
                RolePermissionDTO.builder().roleId(roleDto.getId()).permissionId(i).build()
        ).collect(Collectors.toSet());
        //4.保存角色和权限的关系
        if (CollectionUtils.isNotEmpty(rolePermissionDtoSet)) {
            rolePermissionService.save(rolePermissionDtoSet);
        }
    }

    /**
     * 根据类型和父ID查询权限列表
     *
     * @param code 权限类型
     * @param id   父ID
     * @return 权限信息集合
     */
    private List<PermissionDTO> findByTypeAndPid(Integer code, String id) {
        List<PermissionDTO> permissionDTOS = permissionService.list(PermissionQueryParam
                .builder()
                .type(code)
                .pid(id)
                .build());
        log.info("type为：{}，pid为：{}", code, id);
        return permissionDTOS;
    }

    /**
     * 根据ID获取权限信息
     *
     * @param permId 权限ID
     * @return 权限信息
     */
    private PermissionDTO getPermissionById(String permId) {
        PermissionDTO permissionDTO = permissionService.getOne(PermissionQueryParam
                .builder()
                .id(permId)
                .build());
        BizResponseEnum.PERMISSION_NOT_EXIST.assertNotNullWithMsg(permissionDTO, "id为：" + permId);
        return permissionDTO;
    }

    /**
     * 获取角色信息
     *
     * @param id 角色ID
     * @return 角色信息
     */
    private RoleDTO getRoleById(String id) {
        RoleDTO roleDTO = roleService.getOne(RoleQueryParam
                .builder()
                .id(id)
                .build());
        BizResponseEnum.ROLE_NOT_EXIST.assertNotNullWithMsg(roleDTO, "id为：" + id);
        return roleDTO;
    }

    /**
     * 保存角色
     *
     * @param roleSaveRequest 角色保存信息
     */
    public void save(RoleSaveRequest roleSaveRequest) {
        RoleDTO roleDTO = ConvertUtils.sourceToTarget(roleSaveRequest, RoleDTO.class);
        roleService.save(roleDTO);
    }

    /**
     * 更新角色
     *
     * @param roleUpdateRequest 角色更新请求
     */
    public void update(RoleUpdateRequest roleUpdateRequest) {
        RoleDTO roleDTO = getRoleById(roleUpdateRequest.getId());
        roleDTO.setName(roleUpdateRequest.getId())
                .setCompanyId(roleUpdateRequest.getCompanyId())
                .setDescription(roleUpdateRequest.getDescription());
    }

    /**
     * 删除角色
     *
     * @param roleDeleteRequest 角色ID
     */
    public void delete(RoleDeleteRequest roleDeleteRequest) {
        RoleDTO roleDTO = getRoleById(roleDeleteRequest.getId());
        roleService.delete(roleDTO.getId());
    }

    /**
     * 根据ID查询角色信息
     *
     * @param roleFindByIdRequest 角色ID
     * @return 角色信息
     */
    public RoleFindByIdResponse findById(RoleFindByIdRequest roleFindByIdRequest) {
        RoleDTO roleDTO = getRoleById(roleFindByIdRequest.getId());
        //获取用户的角色信息
        List<RolePermissionDTO> list = rolePermissionService.list(
                RolePermissionQueryParam.builder().roleId(roleFindByIdRequest.getId()).build()
        );
        List<String> permIds = Lists.newArrayList();
        if (CollectionUtils.isNotEmpty(list)) {
            permIds = list.stream().map(RolePermissionDTO::getPermissionId).collect(Collectors.toList());
        }

        return RoleFindByIdResponse
                .builder()
                .id(roleDTO.getId())
                .name(roleDTO.getName())
                .description(roleDTO.getDescription())
                .companyId(roleDTO.getCompanyId())
                .permIds(permIds)
                .build();
    }

    /**
     * 条件分页查询
     *
     * @param roleQueryParam 角色分页查询
     * @return 角色分页信息
     */
    public Page<RoleFindByPageResponse> findByPage(RoleQueryParam roleQueryParam) {
        PageParam<RoleQueryParam> pageParam = new PageParam<RoleQueryParam>()
                .setPage(roleQueryParam.getPage())
                .setLimit(roleQueryParam.getLimit())
                .setParam(roleQueryParam);
        Page<RoleDTO> page = roleService.page(pageParam);
        List<RoleFindByPageResponse> roleFindByPageResponseList = Lists.newArrayList();
        if (CollectionUtils.isNotEmpty(page.getList())) {
            roleFindByPageResponseList = page.getList().stream().map(roleDTO ->
                    ConvertUtils.sourceToTarget(roleDTO, RoleFindByPageResponse.class)
            ).collect(Collectors.toList());
        }
        return Page.succeed(roleFindByPageResponseList, page.getTotal());
    }

    /**
     * 获取所有的角色名称
     *
     * @param companyId 公司ID
     * @return 角色信息
     */
    public RoleFindAllResponse findAll(String companyId) {
        List<RoleDTO> list = roleService.list(RoleQueryParam
                .builder()
                .companyId(companyId)
                .build());
        List<RoleFindAllResponse.RoleFindAllInfo> roleFindAllResponseList = Lists.newArrayList();
        if (CollectionUtils.isNotEmpty(list)) {
            roleFindAllResponseList = list.stream().map(roleDTO ->
                    ConvertUtils.sourceToTarget(roleDTO, RoleFindAllResponse.RoleFindAllInfo.class)
            ).collect(Collectors.toList());
        }
        return RoleFindAllResponse.builder().roleFindAllInfos(roleFindAllResponseList).build();
    }
}
